package xyz.kuailemao.mvc.config;

import com.google.gson.Gson;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import xyz.kuailemao.constant.CrowdConstant;
import xyz.kuailemao.exception.LoginAcctAlreadyInUseException;
import xyz.kuailemao.exception.LoginAcctAlreadyInUseForUpdateException;
import xyz.kuailemao.exception.LoginFailedException;
import xyz.kuailemao.util.CrowdUtil;
import xyz.kuailemao.util.ResultEntity;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 创建时间：2022/8/15 15:20
 * 一个基于注解的异常处理器类
 */
// @ControllerAdvice 表示当前类是一个基于注解的异常处理器类
@ControllerAdvice
public class CrwdExceptionResolver {

    @ExceptionHandler(value = LoginAcctAlreadyInUseForUpdateException.class)
    public ModelAndView resolveLoginAcctAlreadyInUseForUpdateException(LoginAcctAlreadyInUseForUpdateException exception,
                                                    HttpServletRequest request,
                                                    HttpServletResponse response) throws IOException {

        // 异常处理完成后要去的页面
        String viewName = "system-error";

        // 返回 ModelAndView 对象
        return commonResoolve(viewName, exception, request, response);
    }

    @ExceptionHandler(value = LoginAcctAlreadyInUseException.class)
    public ModelAndView resolveLoginAcctAlreadyInUseException(LoginAcctAlreadyInUseException exception,
                                                    HttpServletRequest request,
                                                    HttpServletResponse response) throws IOException {

        // 异常处理完成后要去的页面
        String viewName = "admin-add";

        // 返回 ModelAndView 对象
        return commonResoolve(viewName, exception, request, response);
    }

    @ExceptionHandler(value = Exception.class)
    public ModelAndView resolveException(Exception exception,
                                                    HttpServletRequest request,
                                                    HttpServletResponse response) throws IOException {

        // 异常处理完成后要去的页面
        String viewName = "system-error";

        // 返回 ModelAndView 对象
        return commonResoolve(viewName, exception, request, response);
    }

    @ExceptionHandler(value = LoginFailedException.class)
    public ModelAndView resolveLoginFailedException(LoginFailedException exception,
                                                    HttpServletRequest request,
                                                    HttpServletResponse response) throws IOException {

        // 异常处理完成后要去的页面
        String viewName = "admin-login";

        // 返回 ModelAndView 对象
        return commonResoolve(viewName, exception, request, response);
    }

    /**
     * 算术异常
     *
     * @param exception 异常
     * @param request   请求对象
     * @param response  响应对象
     * @return ModelAndView 对象
     * @throws IOException 抛出异常
     */
    @ExceptionHandler(value = ArithmeticException.class)
    public ModelAndView resolveMathException(ArithmeticException exception, HttpServletRequest request, HttpServletResponse response) throws IOException {

        // 异常处理完成后要去的页面
        String viewName = "system-error";

        // 返回 ModelAndView 对象
        return commonResoolve(viewName, exception, request, response);
    }

    // @ExceptionHandler 将一个具体的异常类型和一个方法关联起来
    @ExceptionHandler(value = NullPointerException.class)
    public ModelAndView resolveNullPointerException(NullPointerException exception, HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 异常处理完成后要去的页面
        String viewName = "system-error";

        // 返回 ModelAndView 对象
        return commonResoolve(viewName, exception, request, response);
    }


    // NullPointerException exception 实际捕获到的异常类型
    // HttpServletRequest request 当前请求对象
    // HttpServletResponse response 当前响应对象

    /**
     * 抽取出来的方法
     *
     * @param viewName  视图名称
     * @param exception 异常类型
     * @param request   请求对象
     * @param response  响应对象
     * @return modelAndView 对象
     * @throws IOException 抛出异常
     */
    private ModelAndView commonResoolve(String viewName,
                                        Exception exception,
                                        HttpServletRequest request,
                                        HttpServletResponse response) throws IOException {
        // 1.判断当前请求类型
        boolean judgeResult = CrowdUtil.judgeRequestType(request);

        // 2.如果是一个 Ajax 请求
        if (judgeResult) {
            // 3.创建一个 ResultEntity对象
            ResultEntity<Object> resultEntity = ResultEntity.failed(exception.getMessage());

            // 4.创建 Gson 对象（转 json）
            Gson gson = new Gson();

            // 5.将 ResultEntity 转换为 JSON 字符串
            String json = gson.toJson(resultEntity);

            // 6.将 JSON 字符串作为响应体返回给浏览器
            response.getWriter().write(json);

            // 7.由于上面已经通过原生的 response 对象返回了响应，所以不提供 ModelAndView 对象
            return null;
        }
        // 8.如果不是 Ajax 请求则创建 ModelAndView 对象
        ModelAndView modelAndView = new ModelAndView();

        // 9.将 Exception 对象存入模型
        modelAndView.addObject(CrowdConstant.ATTR_NAME_EXCEPTION, exception);

        // 10.设置对应的视图名称
        modelAndView.setViewName(viewName);

        // 11.返回 ModelAndView 对象
        return modelAndView;
    }
}
